#!/usr/local/bin/python

import os, difflib, sys, re, time
from numpy import *
import pylab as p
import matplotlib.axes3d as p3
from timeit import Timer

CLASSPATH = "/Applications/Eclipse/plugins/org.antlr_2.7.6/antlr.jar:../../bin"
LDFLAGS = "-framework OpenGL -framework GLUT -lglew"
INCLUDES = "-I../../"
MPX_OBJS = "../../MatPix/util.o ../../MatPix/PBuffer.o"
CFLAGS = "-O -c"

#HAS_GPU=""
HAS_GPU="1"

binops = [["+", "add"], ["-", 'sub'], [".*", 'mul'], ["./", 'div'], 
	   ["==", 'eq'], ["!=", 'neq'], ["<", 'lessthan'], [">", "greaterthan"], 
	   ["<=", "leq"], [">=", "geq"], ["*", "dot"], ["%", "mod"]]
logicops = [["&&", "and"], ["||", "or"]]
post_unops = [["++", "inc"], ["--", "dec"]]
pre_unops = [["'", "trans"]]
all_ops = binops+logicops+logicops+pre_unops
#all_ops = [["+", "add"], ["-", 'sub'], [".*", 'mul'], ["./", 'div'], ["'", "eq"]]
#all_ops = [["+", "add"]]

def mpx_compile(file):
	outfile = os.getcwd()+"/cpp/" + os.path.basename(file) + ".cpp"
	cmd = "java -cp " + CLASSPATH + " Main " + file + " " + outfile + " " + HAS_GPU
	print cmd
	stdin, stdout, stderr = os.popen3(cmd)
	print stdout.read(), stderr.read()
	cpp_compile(outfile)

def cpp_compile(file):
	outfile = file+".o"
	cmd = "g++ " + INCLUDES + " " + CFLAGS + " -o "+ outfile +  " " + file
	print cmd
	stdin, stdout, stderr = os.popen3(cmd)
	print stdout.read(), stderr.read()
	obj_compile(outfile)

def obj_compile(file):
	outfile, ext = os.path.splitext(os.path.basename(file))
	outfile, ext = os.path.splitext(outfile)
	outfile, ext = os.path.splitext(outfile)
	outfile, ext = os.path.splitext(outfile)
	outfile = os.getcwd()+"/bin/" + outfile
	cmd = "	g++ -o " + outfile + " " +  LDFLAGS + " " +  file + " " + MPX_OBJS
	print cmd
	stdin, stdout, stderr = os.popen3(cmd)
	print stdout.read(), stderr.read()
	

def make_op(filename, source):
	mpx = open(filename, 'w')
	mpx.write(source)
	mpx.close()
	os.popen("chmod 755 " + filename)

def build_base(loops, size):
	loop_sz = "_"+str(loops)+"_"+str(size)
	#loop_sz = "_"+str(size)
	mpxdir = os.getcwd()+"/mpx/"
	pydir = os.getcwd()+"/python/" 
	src, npy = make_base(loops, size)
	make_op(mpxdir+"base"+loop_sz + ".txt", src)
	make_op(pydir+"base"+loop_sz + ".py", npy)

def make_base(loops, size):
	src = "matrix A["+str(size)+","+str(size)+"];\n"
	src+= "matrix B["+str(size)+","+str(size)+"];\n"
	src+= "A[:, :] = .25;\n"
	src+= "B[:, :] = .75;\n"
	src+= "print(\"glFinish()\");\n"
	npy = "#!/usr/local/bin/python\n"
	npy+= "from numpy import *\n"
	npy+= "A = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "B = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "A[:,:] = .75*ones((" + str(size) + ", " + str(size) + "))\n"
	npy+= "B[:,:] = .25*ones((" + str(size) + ", " + str(size) + "))\n"
	return src, npy
	
def build_tests(loops, size):
	loop_sz = "_"+str(loops)+"_"+str(size)
	#loop_sz = "_"+str(size)
	mpxdir = os.getcwd()+"/mpx/"
	pydir = os.getcwd()+"/python/" 
	for op in binops:
		opname, filename = op
		src, npy = make_binop(loops, size, opname)
		make_op(mpxdir+filename+loop_sz + ".txt", src)
		make_op(pydir+filename+loop_sz + ".py", npy)
	for op in logicops:
		opname, filename = op
		src, npy = make_logicop(loops, size, opname)
		make_op(mpxdir+filename+loop_sz + ".txt", src)
		make_op(pydir+filename+loop_sz + ".py", npy)
	for op in pre_unops:
		opname, filename = op
		src, npy = make_preunop(loops, size, opname)
		make_op(mpxdir+filename+loop_sz + ".txt", src)
		make_op(pydir+filename+loop_sz + ".py", npy)
	for op in post_unops:
		opname, filename = op
		src, npy = make_postunop(loops, size, opname)
		make_op(mpxdir+filename+loop_sz + ".txt", src)
		make_op(pydir+filename+loop_sz + ".py", npy)

def make_binop(loops, size, op):
	src = "matrix A["+str(size)+","+str(size)+"];\n"
	src+= "matrix B["+str(size)+","+str(size)+"];\n"
	src+= "A[:, :] = .25;\n"
	src+= "B[:, :] = .75;\n"
	src+= "for(i=0:" + str(loops-1) +")\n"		
	src+= "{\n"		
	src+= "A = A " + op + " B;\n"
	src+= "}\n"		
	src+= "print(\"glFinish()\");\n"

#!/usr/bin/python	
	npy = "#!/usr/local/bin/python\n"
	npy+= "from numpy import *\n"
	npy+= "A = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "B = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "A[:,:] = .75*ones((" + str(size) + ", " + str(size) + "))\n"
	npy+= "B[:,:] = .25*ones((" + str(size) + ", " + str(size) + "))\n"
	npy+= "for i in range(" + str(loops) + "):\n"
	if op == ".*":
		npy+= "\tA = A*B\n"
		#npy+= "A = A*B\n"
	elif op == ".*":
		npy+= "\tA = A*B\n"
		#npy+= "A = A*B\n"
	elif op == "./":
		npy+= "\tA = A/B\n"
		#npy+= "A = A/B\n"
	elif op == "*":
		npy+= "\tA = dot(A,B)\n"
		#npy+= "A = dot(A,B)\n"
	else:
		npy+= "\tA = A " + op + "B\n"
		#npy+= "A = A " + op + "B\n"
	return src, npy

def make_logicop(loops, size, op):
	src = "matrix A["+str(size)+","+str(size)+"];\n"
	src+= "matrix B["+str(size)+","+str(size)+"];\n"
	src+= "A[:, :] = .25;\n"
	src+= "B[:, :] = .75;\n"	
	src+= "for(i=0:" + str(loops-1) +")\n"		
	src+= "{\n"		
	src+= "A = A " + op + " B;\n"
	src+= "}\n"		
	src+= "print(\"glFinish()\");\n"
	
	npy = "#!/usr/local/bin/python\n"
	npy+= "from numpy import *\n"
	npy+= "A = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "B = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "A[:,:] = .75*ones((" + str(size) + ", " + str(size) + "))\n"
	npy+= "B[:,:] = .25*ones((" + str(size) + ", " + str(size) + "))\n"
	npy+= "A.dtype=bool\n"
	npy+= "B.dtype=bool\n"	
	npy+= "for i in range(" + str(loops) + "):\n"
	npy+= "\tA = A " + op + "B\n"
	#npy+= "C = A " + op + "B\n"
	return src, npy

def make_postunop(loops, size, op):
	src = "matrix A["+str(size)+","+str(size)+"];\n"
	src+= "A[:, :] = .25;\n"
	src+= "for(i=0:" + str(loops-1) +")\n"		
	src+= "{\n"		
	src+= "B = A" + op + ";\n"
	src+= "}\n"		
	src+= "print(\"glFinish()\");\n"

	npy = "#!/usr/local/bin/python\n"
	npy+= "from numpy import *\n"
	npy+= "A = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "A[:,:] = .75*ones((" + str(size) + ", " + str(size) + "))\n"
	npy+= "for i in range(" + str(loops) + "):\n"
	npy+= "\tA = A +1\n"
#	npy+= "B = A +1\n"
	return src, npy

def make_preunop(loops, size, op):
	src = "matrix A["+str(size)+","+str(size)+"];\n"
	src+= "A[:, :] = .25;\n"
	src+= "for(i=0:" + str(loops-1) +")\n"		
	src+= "{\n"		
	src+= "B = A"+ op + ";\n"
	src+= "}\n"		
	src+= "print(\"glFinish()\");\n"

	npy = "#!/usr/local/bin/python\n"
	npy+= "from numpy import *\n"
	npy+= "A = zeros((" + str(size) + ", " + str(size) + "))\n"
	npy+= "A[:,:] = .75*ones((" + str(size) + ", " + str(size) + "))\n"	
	npy+= "for i in range(" + str(loops) + "):\n"
	npy+= "\tA = A.transpose()\n"
#	npy+= "B = A.transpose()\n"
	return src, npy

loops = 2**array(range(1, 8))
matsize = 2**array(range(6,11))
source_dir = os.getcwd()+"/mpx"
exec_dir = os.getcwd()+"/bin/"
py_dir = os.getcwd()+"/python/"
log = "%16s \t Matpix Speed(ms) \t Python speed(ms)\n" %("operation")

loop = 8
for sz in matsize:
	print "sz: %d" %(sz)
	build_tests(loop, sz)
	build_base(loop, sz)
msz = matsize[size(matsize)-1]
for loop in loops:
	print "loop: %d" %(loop)
	build_tests(loop, msz)
	build_base(loop, sz)

for op in all_ops:
	opname, filename = op
	if not filename == ".svn":
		loop = 8
		for sz in matsize:
			name = filename + "_"+str(loop)+"_"+str(sz) + ".txt"
			#name = filename + "_"+str(sz) + ".txt"
			print "compiling " + filename
			mpx_compile(source_dir + "/" + name)
		for sz in matsize:
			name = "base" + "_"+str(loop)+"_"+str(sz) + ".txt"
			print "compiling " + filename
			mpx_compile(source_dir + "/" + name)

		msz = matsize[size(matsize)-1]
		for loop in loops:
			name = filename + "_"+str(loop)+"_"+str(msz) + ".txt"
			print "compiling " + filename
			mpx_compile(source_dir + "/" + name)
		for loop in loops:
			name = "base" + "_"+str(loop)+"_"+str(msz) + ".txt"
			print "compiling " + filename
			mpx_compile(source_dir + "/" + name)

for op in all_ops:
	opname, filename = op
	if not filename == ".svn":
#	if filename == "add":
		try:
			msz = matsize[size(matsize)-1]
			mpxtime = array(loops, dtype=float)
			pytime = array(loops, dtype=float)
			i=0
			for loop in loops:
				name = filename + "_"+str(loop)+"_"+str(msz)
				base = "base" + "_"+str(loop)+"_"+str(msz)
				#name = filename + "_"+str(msz)
				print "executing " + name
				t = Timer("os.popen('"+exec_dir+name+"')", "import os")
				t2 = Timer("os.popen('"+exec_dir+base+"')", "import os").timeit(1)
				mpxtime[i] = t.timeit(1) - t2
				t = Timer("os.popen('"+py_dir+name+".py')", "import os")
				pytime[i] = t.timeit(1) - t2
				log += "%16s \t %06f \t %06f\n" %(filename, mpxtime[i], pytime[i])
				i+=1
			print log
			make_op(filename+"loops.txt", log)
	
			p.figure(figsize=(12,6))
			p.subplot(121)	
			p.semilogx(loops, mpxtime, 'r', loops, pytime, 'b')
			p.title("execution comparison for " + filename + " operation \n on %dx%d matrix (matrices)" %(msz, msz))
			p.ylabel("execution time(sec)", fontsize=16)
			p.xlabel("iterations", fontsize=16)
			p.legend(("Matpix", "Python"))
			make_op("log/"+filename+"loops.txt", log)

			log=""
			loop = 8
			mpxtime = array(matsize, dtype=float)
			pytime = array(matsize, dtype=float)
			i=0
			for sz in matsize:
				#name = filename + "_"+str(sz)
				name = filename + "_"+str(loop)+"_"+str(sz)
				base = "base" + "_"+str(loop)+"_"+str(msz)
				print "executing " + name
				t = Timer("os.popen('"+exec_dir+name+"')", "import os")
				t2 = Timer("os.popen('"+exec_dir+base+"')", "import os").timeit(1)
				mpxtime[i] = t.timeit(1)-t2
				t = Timer("os.popen('"+py_dir+name+".py')", "import os")
				pytime[i] = t.timeit(1)-t2
				log += "%16s \t %06f \t %06f\n" %(filename, mpxtime[i], pytime[i])
				i+=1
			print log
			make_op("log/"+filename+"sizes.txt", log)
	
			p.subplot(122)	
			p.semilogx(matsize, mpxtime, 'r', matsize, pytime, 'b')
			p.title("execution comparison for 8 iterations \n of " + filename + " operation")
			p.ylabel("execution time(sec)", fontsize=16)
			p.xlabel("length on a side for a square matrix", fontsize=16)
			p.legend(("Matpix", "Python"))
	
			p.savefig("../../../documents/figures/" + filename + ".png")
			#p.show()
		except:
			print "rouble executing " + filename